package com.kantboot.business.gc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.kantboot.business.gc.domain.dto.BusGcGameSearchDTO;
import com.kantboot.business.gc.domain.entity.*;
import com.kantboot.business.gc.domain.vo.BusGcGameCollectAndClickVO;
import com.kantboot.business.gc.domain.vo.BusGcGameVO;
import com.kantboot.business.gc.repository.*;
import com.kantboot.business.gc.service.IBusGcGameService;
import com.kantboot.util.core.param.PageParam;
import com.kantboot.util.core.redis.RedisUtil;
import com.kantboot.util.core.result.PageResult;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class BusGcGameServiceImpl implements IBusGcGameService {

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private BusGcGameVORepository repository;

    @Resource
    private BusGcGameRepository gameRepository;

    @Resource
    private BusGcGameTypeRepository gameTypeRepository;

    @Resource
    private BusGcCollectRepository collectRepository;

    @Resource
    private BusGcUserOpenGameRepository userOpenGameRepository;


    @Override
    public List<BusGcGameVO> getBodyList(BusGcGameSearchDTO param) {
        return repository.getBodyList(param);
    }

    @Override
    public PageResult getBodyData(PageParam<BusGcGameSearchDTO> pageParam) {
        if(pageParam.getData().getTypeId()==null){
            return PageResult.of(repository.getBodyDataByTypeIdIsNull(pageParam.getData(), pageParam.getPageable()));
        }
        return PageResult.of(repository.getBodyData(pageParam.getData(), pageParam.getPageable()));
    }

    @Override
    public BusGcGameVO save(BusGcGameVO vo) {
        // 删除原先的游戏类型
        gameTypeRepository.deleteByGameId(vo.getId());

        BusGcGame vo1= BeanUtil.copyProperties(vo, BusGcGame.class);
        BusGcGame save = gameRepository.save(vo1);

        List<BusGcGameType> gameTypes = new ArrayList<>();
        for (BusGcType type : vo.getTypes()) {
            BusGcGameType gameType = new BusGcGameType();
            gameType.setGameId(save.getId());
            gameType.setTypeId(type.getId());
            gameTypes.add(gameType);
        }
        gameTypeRepository.saveAll(gameTypes);


        return null;
    }


    @Override
    public BusGcGameVO getById(Long id) {
        return repository.findById(id).orElse(null);
    }

    @Override
    public Boolean addClick(Long id) {
        BusGcGame game = gameRepository.findById(id).orElse(null);
        if (game == null) {
            return false;
        }

        String lockKey = "game:click:lock:id:" + id;

        try {
            // 尝试获取分布式锁
            boolean acquiredLock = redisUtil.lock(lockKey);

            if (acquiredLock) {
                game.setClickCount(game.getClickCount() + 1);
                BusGcGame save = gameRepository.save(game);
                if (save == null) {
                    return false;
                }
                // 成功获取到锁
                // 判断 Redis 中的键是否存在
                return true;
            } else {
                //等待200ms后重试
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return addClick(id);
            }
        } finally {
            // 释放锁
            redisUtil.unlock(lockKey);
        }
    }

    @Override
    public List<BusGcGameVO> getTop12() {
        return repository.getTop12Game(PageRequest.of(0, 12));
    }

    @Override
    public PageResult searchGame(PageParam<BusGcGameSearchDTO> pageParam) {
        return PageResult.of(repository.getLimitGame(pageParam.getData(), pageParam.getPageable()));
    }

    @Override
    public BusGcGameCollectAndClickVO getGameCollectAndClick(Long gameId) {
        List<BusGcCollect> collectList = collectRepository.findAllByGameId(gameId);
        List<BusGcUserOpenGame> openGameList = userOpenGameRepository.findAllByGameId(gameId);

        //遍历collectList得到时间戳集合
        List<Long> collectTimeList = collectList.stream().map(BusGcCollect::getGmtCreate).map(Date::getTime).collect(Collectors.toList());
        log.info("collectTimeList:{}",collectTimeList.toString());
        //遍历openGameList得到时间戳集合
        List<Long> openGameTimeList = openGameList.stream().map(BusGcUserOpenGame::getGmtCreate).map(Date::getTime).collect(Collectors.toList());
        log.info("openGameTimeList:{}",openGameTimeList.toString());

//        // 统计每个时间点出现的次数
//        Map<String, Integer> collectCount = new HashMap<>();
//        for (BusGcCollect collect : collectList) {
//            String time = DateUtil.format(collect.getGmtCreate(), "yyyy-MM-dd HH:mm");
//            if (collectCount.containsKey(time)) {
//                collectCount.put(time, collectCount.get(time) + 1);
//            } else {
//                collectCount.put(time, 1);
//            }
//        }
//        Map<String, Integer> openGameCount = new HashMap<>();
//        for (BusGcUserOpenGame openGame : openGameList) {
//            String time = DateUtil.format(openGame.getGmtCreate(), "yyyy-MM-dd HH:mm");
//            if (openGameCount.containsKey(time)) {
//                openGameCount.put(time, openGameCount.get(time) + 1);
//            } else {
//                openGameCount.put(time, 1);
//            }
//        }
//
//        // 添加合并并去重时间戳数据
//        List<String> collectAndOpenGameTime = new ArrayList<>();
//        for (BusGcCollect collect : collectList) {
//            collectAndOpenGameTime.add(DateUtil.format(collect.getGmtCreate(), "yyyy-MM-dd HH:mm"));
//        }
//        for (BusGcUserOpenGame openGame : openGameList) {
//            collectAndOpenGameTime.add(DateUtil.format(openGame.getGmtCreate(), "yyyy-MM-dd HH:mm"));
//        }
//        //将collectAndOpenGameTime升序并去重
//        collectAndOpenGameTime = collectAndOpenGameTime.stream().distinct().sorted().collect(Collectors.toList());
//
//        // 查找并填充数据，如果不存在则填充为0
//        List<Integer> collectCountList = new ArrayList<>();
//        for (String time : collectAndOpenGameTime) {
//            if (collectCount.containsKey(time)) {
//                collectCountList.add(collectCount.get(time));
//            } else {
//                collectCountList.add(0);
//            }
//        }
//        List<Integer> openGameCountList = new ArrayList<>();
//        for (String time : collectAndOpenGameTime) {
//            if (openGameCount.containsKey(time)) {
//                openGameCountList.add(openGameCount.get(time));
//            } else {
//                openGameCountList.add(0);
//            }
//        }
//
//        int maxCollect;
//        if (collectCount.isEmpty()) {
//            maxCollect = 0;
//        } else {
//            maxCollect = Collections.max(collectCount.values());
//        }
//
//        int maxOpenGame;
//        if (openGameCount.isEmpty()) {
//            maxOpenGame = 0;
//        } else {
//            maxOpenGame = Collections.max(openGameCount.values());
//        }



        return new BusGcGameCollectAndClickVO()
                    .setClickTimeData(openGameTimeList)
                    .setCollectTimeData(collectTimeList);
    }

    //获取collectCount最大值
    private Integer getMaxCollectCount(Map<String, Integer> collectCount) {
        Integer max = 0;
        for (Integer value : collectCount.values()) {
            if (value > max) {
                max = value;
            }
        }
        return max;
    }


    @Scheduled(fixedRate = 60000)
    public void batchUpdateClickCount() {
        log.info("正在执行定时任务：batchUpdateClickCount");
        // 尝试获取分布式锁

        // 遍历 Redis 中的键值对，累加点击数
        Map<Long, Long> clickCounts = new HashMap<>();
        redisUtil.keys("game:click:id:*").forEach(key -> {
            Long id = Long.parseLong(key.split(":")[3]);
            Long clickCount = Long.valueOf(redisUtil.get(key));
            clickCounts.put(id, clickCounts.getOrDefault(id, 0L) + clickCount);
        });

        // 更新数据库中的点击数
        clickCounts.forEach((id, clickCount) -> {
            String lockKey = "game:click:lock:id:" + id;
            boolean acquiredLock = redisUtil.lock(lockKey);
            try {
                if (acquiredLock) {
                    BusGcGame game = gameRepository.findById(id).orElse(null);
                    if (game != null) {
                        game.setClickCount(clickCount);
                        gameRepository.save(game);
                        redisUtil.delete("game:click:id:" + id);
                    }
                }else {
                    //跳过等待下次执行
                    return;
                }
            } finally {
                redisUtil.unlock(lockKey);
            }

        });
    }
}
